using System;
using System.Collections.Generic;
using ViScript.Core.ParameterRules;
using ViScript.Core.ParsedSentence;
using ViScript.Core.Utils;

namespace ViScript.Core
{
    public class Engine
    {
        private readonly ILanguageRule languageRule;

        public Engine(ILanguageRule languageRule)
        {
            this.languageRule = languageRule;
        }

        protected Engine()
        {
        }

        public static Engine CreateEngine(params object[] objs)
        {
            return CreateEngine(GetDefaultParameterRules(), objs);
        }

        public static Engine CreateEngine(CompositeParameterRule compositeParameterRule, params object[] objs)
        {
            SentenceRuleFactory sentenceRuleFactory =
                new SentenceRuleFactory(new TextFactory(EscapeStrategy),
                                        compositeParameterRule);
            LanguageRuleFactory languageRuleFactory = new LanguageRuleFactory(sentenceRuleFactory);
            LanguageRule languageRule = languageRuleFactory.CreateLanguageRule(objs);
            compositeParameterRule.Add(typeof (Clause), new ClauseParameterRule(languageRule));
            return new Engine(languageRule);
        }

        public static Base64SerializationBasedEscapeStrategy EscapeStrategy
        {
            get { return new Base64SerializationBasedEscapeStrategy(); }
        }

        public virtual List<IParsedSentence> Parse(IEnumerable<ISentence> sentences)
        {
            List<IParsedSentence> parsedSentences = new List<IParsedSentence>();
            foreach (IParsedSentence parsedSentence in languageRule.Parse(sentences))
            {
                parsedSentences.Add(parsedSentence);
                if (!parsedSentence.IsValid)
                {
                    FireParsingError(parsedSentence);
                }
            }
            return parsedSentences;
        }

        public virtual void FireParsingError(IParsedSentence parsedSentence)
        {
        }

        public void Execute(IEnumerable<ISentence> sentences)
        {
            List<IParsedSentence> parsedSentences = Parse(sentences);
            foreach (IParsedSentence parsedSentence in parsedSentences)
            {
                parsedSentence.Execute();
            }
        }

        public static CompositeParameterRule GetDefaultParameterRules()
        {
            CompositeParameterRule compositeParameterRule = new CompositeParameterRule();
            compositeParameterRule.Add(typeof (Boolean), new BooleanParameterRule());
            compositeParameterRule.Add(typeof (Decimal), new DecimalParameterRule());
            compositeParameterRule.Add(typeof (Double), new DoubleParameterRule());
            compositeParameterRule.Add(typeof (Int16), new Int16ParameterRule());
            compositeParameterRule.Add(typeof (Int32), new Int32ParameterRule());
            compositeParameterRule.Add(typeof (Int64), new Int64ParameterRule());
            compositeParameterRule.Add(typeof (Single), new SingleParameterRule());
            compositeParameterRule.Add(typeof (String), new StringParameterRule());
            return compositeParameterRule;
        }
    }
}